package com.netease.nimlib.lucene.index;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.lukhnos.portmobile.file.Paths;
import org.wltea.analyzer.lucene.IKAnalyzer;

import android.content.Context;
import android.content.SharedPreferences;

import com.netease.nimlib.search.model.NIMIndexException;
import com.netease.nimlib.search.model.NIMIndexRecord;

public final class LuceneWriter {
	private final String TAG_VERSION = "VERSION";

	private final Context context;
	private final String path;
	private Directory dir;
	private IndexWriter writer;

	public LuceneWriter(Context context, String path) {
		this.context = context;
		this.path = path;
	}

	public final void open() throws NIMIndexException {
		try {
			dir = FSDirectory.open(Paths.get(path));
			writer = new IndexWriter(dir, new IndexWriterConfig(new IKAnalyzer()));
		} catch (IOException e) {
			throw new NIMIndexException(e.getMessage());
		}
	}

	public final void close() {
		try {
			if (writer != null) {
				writer.close();
				writer = null;
			}

			if (dir != null) {
				dir.close();
				dir = null;
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public final void insert(NIMIndexRecord record) throws NIMIndexException {
		List<NIMIndexRecord> records = new ArrayList<>(1);
		records.add(record);
		insert(record);
	}

	public final void insert(Collection<NIMIndexRecord> records) throws NIMIndexException {
		if (records == null || records.isEmpty() || writer == null) {
			return;
		}

		try {
			for (NIMIndexRecord record : records) {
				writer.addDocument(MsgDocConverter.buildDoc(record));
			}
			writer.commit();
		} catch (IOException e) {
			throw new NIMIndexException(e.getMessage());
		}
	}

	public final void delete(long type, long dataid) throws NIMIndexException {
		if (writer == null) {
			return;
		}

		try {
			// build query
			Query q1 = new TermQuery(new Term(MsgDocFieldName.DATAID, ((Long) dataid).toString()));
			Query q2 = new TermQuery(new Term(MsgDocFieldName.TYPE, ((Long) type).toString()));
			BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
			booleanQuery.add(q1, BooleanClause.Occur.MUST);
			booleanQuery.add(q2, BooleanClause.Occur.MUST);
			// delete
			writer.deleteDocuments(booleanQuery.build());
			writer.commit();
		} catch (IOException e) {
			throw new NIMIndexException(e.getMessage());
		}
	}

	public final void delete(long type, String id) throws NIMIndexException {
		if (writer == null) {
			return;
		}

		try {
			// build query
			Query q1 = new TermQuery(new Term(MsgDocFieldName.ID, id));
			Query q2 = new TermQuery(new Term(MsgDocFieldName.TYPE, ((Long) type).toString()));
			BooleanQuery.Builder booleanQuery = new BooleanQuery.Builder();
			booleanQuery.add(q1, BooleanClause.Occur.MUST);
			booleanQuery.add(q2, BooleanClause.Occur.MUST);
			// delete
			writer.deleteDocuments(booleanQuery.build());
			writer.commit();
		} catch (IOException e) {
			throw new NIMIndexException(e.getMessage());
		}
	}

	public final void delete(long type) throws NIMIndexException {
		if (writer == null) {
			return;
		}

		try {
			writer.deleteDocuments(new Term(MsgDocFieldName.TYPE, ((Long) type).toString()));
			writer.commit();
		} catch (IOException e) {
			throw new NIMIndexException(e.getMessage());
		}
	}

	public final void deleteAll() throws NIMIndexException {
		if (writer == null) {
			return;
		}

		try {
			writer.deleteAll();
			writer.commit();
		} catch (IOException e) {
			throw new NIMIndexException(e.getMessage());
		}
	}

	public final long getVersion() {
		return getLong(TAG_VERSION, 0L);
	}

	public final void setVersion(long ver) {
		saveLong(TAG_VERSION, ver);
	}

	private long getLong(String key, long defValue) {
		return getSharedPreferences().getLong(key, defValue);
	}

	private void saveLong(String key, long value) {
		SharedPreferences.Editor editor = getSharedPreferences().edit();
		editor.putLong(key, value);
		editor.commit();
	}

	private SharedPreferences getSharedPreferences() {
		// TODO:TO REPLACE ACCOUNT
		return context.getSharedPreferences("LUCENE." + "hjtest1", Context.MODE_PRIVATE);
	}
}